fs: add support for async iterators to fs.writeFile#38525
fs: add support for async iterators to fs.writeFile#38525yagipy wants to merge 4 commits intonodejs:mainfrom
fs.writeFile#38525Conversation
675ffcd to
9a563a1
Compare
9a563a1 to
c9bba3f
Compare
lib/fs.js
Outdated
| if (writeErr) { | ||
| if (isUserFd) { | ||
| callback(writeErr); | ||
| } else { | ||
| fs.close(fd, (err) => { | ||
| callback(aggregateTwoErrors(err, writeErr)); | ||
| }); | ||
| } |
There was a problem hiding this comment.
I think that in general it would make more sense to continue iterating only after a write has finished.
There was a problem hiding this comment.
Agreed. As it is this will have issues with backpressure, risking flooding the destination with pending write requests. Also, I'm missing the bit about exiting the for await if the fs.write() errors on any single iteration.
lib/fs.js
Outdated
| ); | ||
| } | ||
| fs.close(fd, callback); | ||
| })(); |
There was a problem hiding this comment.
There's no catch handler on the promise being returned here.
lib/fs.js
Outdated
| } | ||
| // write(fd, buffer, offset, length, position, callback) | ||
| if (isCustomIterable(buffer)) { | ||
| (async () => { |
There was a problem hiding this comment.
It would be clearer and more maintainable to separate this out into a separate top-level function.
lib/fs.js
Outdated
| } | ||
| ); | ||
| } | ||
| fs.close(fd, callback); |
There was a problem hiding this comment.
The close here is problematic because writes may still be pending from the loop.
test/parallel/test-fs-write-file.js
Outdated
| process.nextTick(() => controller.abort()); | ||
| } | ||
|
|
||
| { |
There was a problem hiding this comment.
It would be better to separate the tests for the new functionality into a separate isolated test file.
jasnell
left a comment
There was a problem hiding this comment.
It's a good idea but the implementation needs work.
a7cc927 to
3313df8
Compare
3313df8 to
785d76d
Compare
lib/fs.js
Outdated
| if (writeErr) { | ||
| handleWriteAllErrorCallback(fd, isUserFd, writeErr, callback); | ||
| } else { | ||
| writeAll(fd, isUserFd, buffer, offset, |
There was a problem hiding this comment.
I think that there's a mistake here that also exists in the fs/promises version, where the code assumes that the whole chunk has been written but it might have only been partially written.
ba733d5 to
ccdb3d1
Compare
ccdb3d1 to
6f21783
Compare
176573e to
c0b87d6
Compare
|
@Linkgoron I added the following test based on this test, but I was not able to reproduce the mistake. 😓 (The current implementation will pass.) |
It's quite difficult to reproduce, and I'm not sure in which cases |
|
@Linkgoron |
mcollina
left a comment
There was a problem hiding this comment.
Good work! I've left a few notes on the implementation.
| writeAllCustomIterable( | ||
| fd, isUserFd, buffer, offset, length, signal, encoding, callback) | ||
| .catch((reason) => { | ||
| handleWriteAllErrorCallback(fd, isUserFd, reason, callback); |
There was a problem hiding this comment.
I would schedule this via process.nextTick. If this throws synchronously for whatever reason, it will lead to an unhandled rejection.
| }); | ||
| } | ||
|
|
||
| async function writeAllCustomIterable( |
There was a problem hiding this comment.
Do not use async with a callback. Mixing those two can only lead to bugs. I would recommend having a promisified version of fs.write() and just use async/await.
There was a problem hiding this comment.
@mcollina Thanks for your suggestion 👍 . I'm curious about the advantages of having a promisified version of fs.write() and using async/await. Could you elaborate on why this approach might be better than mixing async with a callback? I'm interested in understanding the potential benefits and how it could prevent bugs.
Fixes: #38075
Checklist